(ns clojure-demo.core)
 (:use '[clojure.java.io])
 
(def arr (make-array Double/TYPE 1000 1000))
;= #'user/arr

(time (dotimes [i 1000]
	(dotimes [j 1000]
		(aset arr i j 1.0)
		(aget arr i j))))
; "Elapsed time: 50802.798 msecs"

(time (dotimes [i 1000]
	(dotimes [j 1000]
		(let [^doubles darr (aget ^objects arr i)]
			(aset darr j 1.0)
			(aget darr j)))))
; "Elapsed time: 21.543 msecs"
;= nil

(defmacro deep-aget
	"Gets a value from a multidimensional array as if via `aget`,
	but with automatic application of appropriate type hints to
	each step in the array traversal as guided by the hint added
	to the source array.
	e.g. (deep-aget ^doubles arr i j)"

	([array idx]
		`(aget ~array ~idx)) 
	([array idx & idxs]
		(let [a-sym (gensym "a")]
			`(let [~a-sym (aget ~(vary-meta array assoc :tag 'objects) ~idx)] 
				(deep-aget ~(with-meta a-sym {:tag (-> array meta :tag)}) ~@idxs)))))

;--
(defmacro deep-aset
	"Sets a value in a multidimensional array as if via `aset`,
	but with automatic application of appropriate type hints to
	each step in the array traversal as guided by the hint added
	to the target array.
	e.g. (deep-aset ^doubles arr i j 1.0)"
	[array & idxsv]
	(let [hints '{booleans boolean, bytes byte 
		chars char, longs long
		ints int, shorts short
		doubles double, floats float}

		hint (-> array meta :tag)
		[v idx & sxdi] (reverse idxsv)
		idxs (reverse sxdi)
		v (if-let [h (hints hint)] (list h v) v)

		nested-array (if (seq idxs)
		`(deep-aget ~(vary-meta array assoc :tag 'objects) ~@idxs)
		array)

		a-sym (gensym "a")]

		`(let [~a-sym ~nested-array]
			(aset ~(with-meta a-sym {:tag hint}) ~idx ~v))))

;使用示例：
(time (dotimes [i 1000]
	(dotimes [j 1000]
		(deep-aset ^doubles arr i j 1.0)
		(deep-aget ^doubles arr i j))))
; "Elapsed time: 25.033 msecs"

 (macroexpand-1 '(deep-aset ^doubles arr 2 3 1.0))
;(clojure.core/let [a1335 (user/deep-aget arr 2)] (clojure.core/aset a1335 3 (double 1.0)))

(def arr (make-array Double/TYPE 100 100 100))
 (macroexpand-1 '(deep-aset ^doubles arr 2 3 4 1.0))
;(clojure.core/let [a1366 (user/deep-aget arr 2 3)] (clojure.core/aset a1366 4 (double 1.0)))

(macroexpand `(deep-aset ^doubles arr 2 3 4 1.0))
;(let* [a1376 (user/deep-aget user/arr 2 3)] (clojure.core/aset a1376 4 1.0))

 (macroexpand '(.. arm getHand getFinger))
;(. (. arm getHand) getFinger)
 (macroexpand-1 '(.. arm getHand getFinger))
;(.. (. arm getHand) getFinger)

 (use '[clojure.pprint])
;pprint
(pprint (macroexpand-1 '(deep-aset ^doubles arr 2 3 4 1.0)))
;(clojure.core/let
; [a1558 (user/deep-aget arr 2 3)]
; (clojure.core/aset a1558 4 (double 1.0)))


